package com.lxm.framework.mybatisplus;

import cn.beecp.BeeDataSource;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.lxm.framework.common.utils.StringFormatUtils;
import com.lxm.framework.mybatisplus.extention.injector.CustomizedInjector;
import com.lxm.framework.mybatisplus.interceptor.ParameterInterceptor;
import com.lxm.framework.mybatisplus.interceptor.StatementInterceptor;
import com.lxm.framework.mybatisplus.util.DataSourceUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;

import java.util.Properties;

/**
 * @Author: Lys
 * @Date 2022/3/1
 * @Describe
 **/

@EnableConfigurationProperties({DataSourceProperties.class, MybatisPlusConfigProperties.class})
@MapperScan(basePackages = {"com.lxm.*.*.persistence.inf"}, sqlSessionFactoryRef = "sqlSessionFactory")
@Configuration
public class MybatisPlusConfig {

    @Bean("beeDataSource")
    public BeeDataSource beeDataSource(DataSourceProperties dataSourceProperties) {
        var beeDataSource = DataSourceUtils.createBeeDataSource(dataSourceProperties);
        String dbName = dataSourceProperties.getName();
        if (StringUtils.isBlank(dbName)) {
            dbName = StringFormatUtils.getDbName(dataSourceProperties.getUrl());
        }
        beeDataSource.setPoolName(dbName);
        return beeDataSource;
    }

    /*@Bean("druidDataSource")
    public DruidDataSource druidDataSource(DataSourceProperties dataSourceProperties) {
        var druidDataSource = DataSourceUtils.createDruidDataSource();
        String dbName = dataSourceProperties.getName();
        if (StringUtils.isBlank(dbName)) {
            dbName = StringFormatUtils.getDbName(dataSourceProperties.getUrl());
        }
        druidDataSource.setName(dbName);
        druidDataSource.setUrl(dataSourceProperties.getUrl());
        druidDataSource.setUsername(dataSourceProperties.getUsername());
        druidDataSource.setPassword(dataSourceProperties.getPassword());
        return druidDataSource;
    }*/

    @Bean("parameterInterceptor")
    public ParameterInterceptor parameterInterceptor() {
        return new ParameterInterceptor();
    }

    @Bean("statementInterceptor")
    public StatementInterceptor statementInterceptor() {
        return new StatementInterceptor();
    }

    @Bean("globalConfig")
    public GlobalConfig globalConfig() {
        var dbConfig = new GlobalConfig.DbConfig();
        //主键类型  0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
        dbConfig.setIdType(IdType.INPUT);
        dbConfig.setLogicDeleteValue("1")
                .setLogicNotDeleteValue("0");
        var config = new GlobalConfig();
        return config.setDbConfig(dbConfig)
                .setBanner(false)
                .setSqlInjector(new CustomizedInjector());
    }

    /*@Bean("transactionManager")
    @DependsOn("druidDataSource")
    public PlatformTransactionManager transactionManager(@Qualifier("druidDataSource") DruidDataSource druidDataSource) {
        return new DataSourceTransactionManager(druidDataSource);
    }*/

    @Bean("transactionManager")
    @DependsOn("beeDataSource")
    public PlatformTransactionManager transactionManager(@Qualifier("beeDataSource") BeeDataSource beeDataSource) {
        return new DataSourceTransactionManager(beeDataSource);
    }

    @Bean("txInterceptor")
    @DependsOn("transactionManager")
    public TransactionInterceptor txInterceptor(@Qualifier("transactionManager") PlatformTransactionManager transactionManager) {
        var properties = new Properties();
        properties.setProperty("*", "PROPAGATION_REQUIRED,-Exception");
        NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource();
        tas.setProperties(properties);
        var trans = new TransactionInterceptor();
        trans.setTransactionManager(transactionManager);
        trans.setTransactionAttributeSource(tas);
        return trans;
    }

    @Bean("txAdvisor")
    @DependsOn("txInterceptor")
    public AspectJExpressionPointcutAdvisor txAdvisor(@Qualifier("txInterceptor") TransactionInterceptor txInterceptor, MybatisPlusConfigProperties mybatisPlusConfigProperties) {
        var pointCutAdvisor = new AspectJExpressionPointcutAdvisor();
        pointCutAdvisor.setAdvice(txInterceptor);
        pointCutAdvisor.setExpression(mybatisPlusConfigProperties.getExpression());
        return pointCutAdvisor;
    }

    @Bean("sqlSessionFactory")
    @DependsOn({"beeDataSource", "globalConfig", "parameterInterceptor", "statementInterceptor"})
    public SqlSessionFactory sqlSessionFactory(@Qualifier("beeDataSource") BeeDataSource druidDataSource,
                                               @Qualifier("globalConfig") GlobalConfig globalConfig,
                                               @Qualifier("parameterInterceptor") ParameterInterceptor parameterInterceptor,
                                               @Qualifier("statementInterceptor") StatementInterceptor statementInterceptor,
                                               MybatisPlusConfigProperties mybatisPlusConfigProperties
    ) throws Exception {
        var configuration = new MybatisConfiguration();
        configuration.setJdbcTypeForNull(mybatisPlusConfigProperties.getJdbcTypeForNull());
        configuration.setCacheEnabled(false);
        configuration.setMapUnderscoreToCamelCase(mybatisPlusConfigProperties.isMapUnderscoreToCamelCase());
        configuration.setCallSettersOnNulls(mybatisPlusConfigProperties.isCallSettersOnNulls());

        var sqlSessionFactory = new MybatisSqlSessionFactoryBean();
        sqlSessionFactory.setDataSource(druidDataSource);
        sqlSessionFactory.setTypeAliasesPackage(mybatisPlusConfigProperties.getTypeAliasesPackage());
        var pathResolver = new PathMatchingResourcePatternResolver();
        Resource[] resources = pathResolver.getResources(mybatisPlusConfigProperties.getResourcePathPattern());
        sqlSessionFactory.setMapperLocations(resources);

        sqlSessionFactory.setConfiguration(configuration);
        sqlSessionFactory.setPlugins(parameterInterceptor, statementInterceptor);
        sqlSessionFactory.setGlobalConfig(globalConfig);
        return sqlSessionFactory.getObject();
    }
}
